commonlibsse_ng\re\u/
UI.rs

1use core::ffi::{CStr, c_void};
2
3use crate::re::BSAtomic::BSSpinLock;
4use crate::re::BSFixedString::BSFixedString;
5use crate::re::BSTArray::BSTArray;
6use crate::re::BSTEvent::{BSTEventSink, BSTEventSource};
7use crate::re::BSTHashMap::BSTHashMap;
8use crate::re::BSTimer::BSTimer;
9use crate::re::GFxMovieView;
10use crate::re::GPtr::GPtr;
11use crate::re::IMenu::IMenu;
12use crate::re::MenuModeChangeEvent::MenuModeChangeEvent;
13use crate::re::MenuOpenCloseEvent::MenuOpenCloseEvent;
14
15#[rustfmt::skip]
16#[repr(C)]
17#[derive(Debug)]
18pub struct UI {
19    pub __base : [u8; 8],                                // 0x000 non Empty base optimization: BSTSingletonSDM
20    pub __base1: BSTEventSource<MenuOpenCloseEvent>,     // 0x008
21    pub __base2: BSTEventSource<MenuModeChangeEvent>,    // 0x060
22    pub __base3: BSTEventSource<*mut c_void>,            // 0x0B8 MenuModeCounterChangedEvent/TutorialEvent
23    pub menuStack: BSTArray<GPtr<IMenu>>,                // 0x110
24    pub menuMap: BSTHashMap<BSFixedString, UIMenuEntry>, // 0x128
25    pub processMessagesLock: BSSpinLock,                 // 0x158
26    pub numPausesGame: u32,                              // 0x160 (= 0) += 1 if (i_menu->flags & 0x00001)
27    pub numItemMenus: u32,                               // 0x164 (= 0) += 1 if (i_menu->flags & 0x02000)
28    pub numDisablePauseMenu: u32,                        // 0x168 (= 0) += 1 if (i_menu->flags & 0x00080)
29    pub numAllowSaving: u32,                             // 0x16C (= 0) += 1 if (i_menu->flags & 0x00800)
30    pub numDontHideCursorWhenTopmost: u32,               // 0x170 (= 0) += 1 if (i_menu->flags & 0x04000)
31    pub numCustomRendering: u32,                         // 0x174 (= 0) += 1 if (i_menu->flags & 0x08000)
32    pub numApplicationMenus: u32,                        // 0x178 (= 0) += 1 if (i_menu->flags & 0x20000)
33    pub modal: bool,                                     // 0x17C (= 0)  = 1 if (i_menu->flags & 0x00010)
34    pub pad17D: u8,                                      // 0x17D
35    pub pad17E: u16,                                     // 0x17E
36    pub uiTimer: BSTimer,                                // 0x180
37    pub menuSystemVisible: bool,                         // 0x1C0
38    pub closingAllMenus: bool,                           // 0x1C1
39    pub pad1C2: u16,                                     // 0x1C2
40    pub pad1C4: u32,                                     // 0x1C4
41    pub unk1C8: u32,                                     // 0x1C8 - VR
42    pub unk1CA: u32,                                     // 0x1CA - VR
43}
44const _: () = assert!(core::mem::size_of::<UI>() == 0x1D0);
45
46pub trait HasMenuName {
47    const MENU_NAME: &'static CStr;
48}
49
50impl UI {
51    /// Returns a reference to the singleton instance of `UI`, if available.
52    #[commonlibsse_ng_derive_internal::relocate(
53        cast_as = "*mut *mut UI",
54        default = "None",
55        deref_once,
56        id(se = 514178, ae = 400327)
57    )]
58    #[inline]
59    pub fn get_singleton() -> Option<&'static UI> {
60        |deref_type: DerefType| unsafe { deref_type.as_ref() }
61    }
62
63    /// Returns a mutable reference to the singleton instance of `UI`, if available.
64    #[commonlibsse_ng_derive_internal::relocate(
65        cast_as = "*mut *mut UI",
66        default = "None",
67        deref_once,
68        id(se = 514178, ae = 400327)
69    )]
70    #[inline]
71    pub fn get_singleton_mut() -> Option<&'static mut UI> {
72        |deref_type: DerefType| unsafe { deref_type.as_mut() }
73    }
74
75    /// Returns true if the game is currently paused.
76    #[inline]
77    pub const fn game_is_paused(&self) -> bool {
78        self.numPausesGame > 0
79    }
80
81    /// Gets a pointer to the specified menu if it is currently registered.
82    #[inline]
83    pub fn get_menu(&self, menu_name: &CStr) -> Option<GPtr<IMenu>> {
84        self.menuMap
85            .get(&BSFixedString::new(menu_name))
86            .map(|menu_entry| GPtr::clone(&menu_entry.menu))
87    }
88
89    /// Gets the `GFxMovieView` associated with the specified menu.
90    #[inline]
91    pub fn get_movie_view(&self, menu_name: &CStr) -> Option<GPtr<GFxMovieView>> {
92        self.get_menu(menu_name).map(|menu_ptr| GPtr::clone(&menu_ptr.uiMovie))
93    }
94
95    /// Returns true if the cursor should be hidden when this UI is the topmost.
96    #[inline]
97    pub const fn is_cursor_hidden_when_topmost(&self) -> bool {
98        self.numDontHideCursorWhenTopmost == 0
99    }
100
101    /// Returns true if an inventory/item menu is currently open.
102    #[inline]
103    pub const fn is_item_menu_open(&self) -> bool {
104        self.numItemMenus > 0
105    }
106
107    /// Checks whether a given menu is currently open and on the stack.
108    #[inline]
109    pub fn is_menu_open(&self, menu_name: &CStr) -> bool {
110        self.get_menu(menu_name).is_some_and(|menu_ptr| menu_ptr.on_stack())
111    }
112
113    /// Returns true if any modal menu is currently open.
114    #[inline]
115    pub const fn is_modal_menu_open(&self) -> bool {
116        self.modal
117    }
118
119    /// Returns true if the pause menu is currently disabled.
120    #[inline]
121    pub const fn is_pause_menu_disabled(&self) -> bool {
122        self.numDisablePauseMenu > 0
123    }
124
125    /// Returns true if saving the game is currently allowed.
126    #[inline]
127    pub const fn is_saving_allowed(&self) -> bool {
128        self.numAllowSaving > 0
129    }
130
131    /// Returns true if the menu system is currently being displayed.
132    #[inline]
133    pub const fn is_showing_menus(&self) -> bool {
134        self.menuSystemVisible
135    }
136
137    /// Returns true if custom rendering is being used for menus.
138    #[inline]
139    pub const fn is_using_custom_rendering(&self) -> bool {
140        self.numCustomRendering > 0
141    }
142
143    /// Registers a new menu with the UI system.
144    #[inline]
145    pub fn register(&mut self, menu_name: &CStr, creator: fn() -> *mut IMenu) {
146        self.menuMap.insert(BSFixedString::new(menu_name), UIMenuEntry::new(GPtr::null(), creator));
147    }
148
149    /// Sets whether the UI system should be visible.
150    #[inline]
151    pub const fn show_menus(&mut self, show: bool) {
152        self.menuSystemVisible = show;
153    }
154
155    #[inline]
156    pub fn get_menu_by_name<T>(&self, name: &CStr) -> Option<GPtr<T>>
157    where
158        T: crate::re::GPtr::RefCounted,
159    {
160        self.get_menu(name).map(|menu_ptr| menu_ptr.cast::<T>())
161    }
162
163    #[inline]
164    pub fn get_menu_as<T>(&self) -> Option<GPtr<T>>
165    where
166        T: HasMenuName + crate::re::GPtr::RefCounted,
167    {
168        self.get_menu_by_name::<T>(T::MENU_NAME)
169    }
170}
171
172macro_rules! impl_ui_event_sink {
173    (
174        $(
175            ($add_fn:ident, $remove_fn:ident, $field:ident, $event_ty:ty)
176        ),*
177        $(,)?
178    ) => {
179        impl UI {
180            $(
181                pub fn $add_fn(&mut self, sink: *mut BSTEventSink<$event_ty>) {
182                    self.$field.add_event_sink(sink);
183                }
184
185                pub fn $remove_fn(&mut self, sink: *mut BSTEventSink<$event_ty>) {
186                    self.$field.remove_event_sink(sink);
187                }
188            )*
189        }
190    };
191}
192impl_ui_event_sink! {
193    (add_menu_open_close_sink, remove_menu_open_close_sink, __base1, MenuOpenCloseEvent),
194    (add_menu_mode_change_sink, remove_menu_mode_change_sink, __base2, MenuModeChangeEvent),
195    (add_void_sink, remove_void_sink, __base3, *mut c_void),
196}
197
198#[repr(C)]
199#[derive(Debug)]
200pub struct UIMenuEntry {
201    pub menu: GPtr<IMenu>,               // 0x0
202    pub menuCreator: fn() -> *mut IMenu, // 0x8
203}
204const _: () = assert!(core::mem::size_of::<UIMenuEntry>() == 0x10);
205
206impl UIMenuEntry {
207    #[inline]
208    pub const fn new(menu: GPtr<IMenu>, menu_creator: fn() -> *mut IMenu) -> Self {
209        Self { menu, menuCreator: menu_creator }
210    }
211}